home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / language / pcl_src.zoo / iterate.lsp < prev    next >
Encoding:
Lisp/Scheme  |  1992-07-09  |  62.0 KB  |  1,270 lines

  1. ;;;-*- Package: ITERATE; Syntax: Common-Lisp; Base: 10 -*-
  2. ;;;
  3. ;;; *************************************************************************
  4. ;;; Copyright (c) 1985, 1986, 1987, 1988, 1989, 1990 Xerox Corporation.
  5. ;;; All rights reserved.
  6. ;;;
  7. ;;; Use and copying of this software and preparation of derivative works
  8. ;;; based upon this software are permitted.  Any distribution of this
  9. ;;; software or derivative works must comply with all applicable United
  10. ;;; States export control laws.
  11. ;;; 
  12. ;;; This software is made available AS IS, and Xerox Corporation makes no
  13. ;;; warranty about the software, its performance or its conformity to any
  14. ;;; specification.
  15. ;;; 
  16. ;;; Any person obtaining a copy of this software is requested to send their
  17. ;;; name and post office or electronic mail address to:
  18. ;;;   CommonLoops Coordinator
  19. ;;;   Xerox PARC
  20. ;;;   3333 Coyote Hill Rd.
  21. ;;;   Palo Alto, CA 94304
  22. ;;; (or send Arpanet mail to CommonLoops-Coordinator.pa@Xerox.arpa)
  23. ;;;
  24. ;;; Suggestions, comments and requests for improvements are also welcome.
  25. ;;; *************************************************************************
  26. ;;; 
  27. ;;; Original source {pooh/n}<pooh>vanmelle>lisp>iterate;4 created 27-Sep-88 12:35:33
  28.  
  29. (in-package :iterate :use '(:lisp :walker))
  30.    
  31.  
  32. (export '(iterate iterate* gathering gather with-gathering interval elements 
  33.                 list-elements list-tails plist-elements eachtime while until 
  34.                 collecting joining maximizing minimizing summing 
  35.                 *iterate-warnings*))
  36.  
  37. (defvar *iterate-warnings* :any "Controls whether warnings are issued for iterate/gather forms that aren't optimized.
  38. NIL => never; :USER => those resulting from user code; T => always, even if it's the iteration macro that's suboptimal."
  39.        )
  40.  
  41. ;;; ITERATE macro
  42.  
  43.  
  44. (defmacro iterate (clauses &body body &environment env)
  45.        (optimize-iterate-form clauses body env))
  46.  
  47. (defun
  48.  simple-expand-iterate-form
  49.  (clauses body)
  50.  
  51.  ;; Expand ITERATE.  This is the "formal semantics" expansion, which we never
  52.  ;; use.
  53.  (let*
  54.   ((block-name (gensym))
  55.    (bound-var-lists (mapcar #'(lambda (clause)
  56.                                      (let ((names (first clause)))
  57.                                           (if (listp names)
  58.                                               names
  59.                                               (list names))))
  60.                            clauses))
  61.    (generator-vars (mapcar #'(lambda (clause)
  62.                                     (declare (ignore clause))
  63.                                     (gensym))
  64.                           clauses)))
  65.   `(block ,block-name
  66.        (let*
  67.         ,(mapcan #'(lambda (gvar clause var-list)
  68.                                                ; For each clause, bind a
  69.                                                ; generator temp to the clause,
  70.                                                ; then bind the specified
  71.                                                ; var(s)
  72.                           (cons (list gvar (second clause))
  73.                                 (copy-list var-list)))
  74.                 generator-vars clauses bound-var-lists)
  75.         
  76.         ;; Note bug in formal semantics: there can be declarations in the head
  77.         ;; of BODY; they go here, rather than inside loop
  78.         (loop
  79.          ,@(mapcar
  80.             #'(lambda (var-list gen-var)
  81.                                                ; Set each bound variable (or
  82.                                                ; set of vars) to the result of
  83.                                                ; calling the corresponding
  84.                                                ; generator
  85.                      `(multiple-value-setq
  86.                        ,var-list
  87.                        (funcall ,gen-var #'(lambda nil (return-from
  88.                                                         ,block-name)))))
  89.             bound-var-lists generator-vars)
  90.          ,@body)))))
  91.  
  92. (defparameter *iterate-temp-vars-list*
  93.        '(iterate-temp-1 iterate-temp-2 iterate-temp-3 iterate-temp-4 
  94.                iterate-temp-5 iterate-temp-6 iterate-temp-7 iterate-temp-8)
  95.        "Temp var names used by ITERATE expansions.")
  96.  
  97. (defun
  98.  optimize-iterate-form
  99.  (clauses body iterate-env)
  100.  (let*
  101.   ((temp-vars *iterate-temp-vars-list*)
  102.    (block-name (gensym))
  103.    (finish-form `(return-from ,block-name))
  104.    (bound-vars (mapcan #'(lambda (clause)
  105.                                 (let ((names (first clause)))
  106.                                      (if (listp names)
  107.                                          (copy-list names)
  108.                                          (list names))))
  109.                       clauses))
  110.    iterate-decls generator-decls update-forms bindings leftover-body)
  111.   (do ((tail bound-vars (cdr tail)))
  112.       ((null tail))
  113.                                                ; Check for duplicates
  114.     (when (member (car tail)
  115.                  (cdr tail))
  116.         (warn "Variable appears more than once in ITERATE: ~S" (car tail))))
  117.   (flet
  118.    ((get-iterate-temp nil 
  119.  
  120.            ;; Make temporary var.  Note that it is ok to re-use these symbols
  121.            ;; in each iterate, because they are not used within BODY.
  122.            (or (pop temp-vars)
  123.                (gensym))))
  124.    (dolist (clause clauses)
  125.        (cond
  126.         ((or (not (consp clause))
  127.              (not (consp (cdr clause))))
  128.          (warn "Bad syntax in ITERATE: clause not of form (var iterator): ~S" 
  129.                clause))
  130.         (t
  131.          (unless (null (cddr clause))
  132.                 (warn 
  133.        "Probable parenthesis error in ITERATE clause--more than 2 elements: ~S"
  134.                       clause))
  135.          (multiple-value-bind
  136.           (let-body binding-type let-bindings localdecls otherdecls extra-body)
  137.           (expand-into-let (second clause)
  138.                  'iterate iterate-env)
  139.           
  140.           ;; We have expanded the generator clause and parsed it into its LET
  141.           ;; pieces.
  142.           (prog*
  143.            ((vars (first clause))
  144.             gen-args renamed-vars)
  145.            (setq vars (if (listp vars)
  146.                           (copy-list vars)
  147.                           (list vars)))
  148.                                                ; VARS is now a (fresh) list of
  149.                                                ; all iteration vars bound in
  150.                                                ; this clause
  151.            (cond
  152.             ((eq let-body :abort)
  153.                                                ; Already issued a warning
  154.                                                ; about malformedness
  155.              )
  156.             ((null (setq let-body (function-lambda-p let-body 1)))
  157.                                                ; Not of the expected form
  158.              (let ((generator (second clause)))
  159.                   (cond ((and (consp generator)
  160.                               (fboundp (car generator)))
  161.                                                ; It looks ok--a macro or
  162.                                                ; function here--so the guy who
  163.                                                ; wrote it just didn't do it in
  164.                                                ; an optimizable way
  165.                          (maybe-warn :definition "Could not optimize iterate clause ~S because generator not of form (LET[*] ... (FUNCTION (LAMBDA (finish) ...)))"
  166.                                 generator))
  167.                         (t                     ; Perhaps it's just a
  168.                                                ; misspelling?  Probably user
  169.                                                ; error
  170.                            (maybe-warn :user 
  171.                                 "Iterate operator in clause ~S is not fboundp."
  172.                                   generator)))
  173.                   (setq let-body :abort)))
  174.             (t
  175.              
  176.              ;; We have something of the form #'(LAMBDA (finisharg) ...),
  177.              ;; possibly with some LET bindings around it.  LET-BODY =
  178.              ;; ((finisharg) ...).
  179.              (setq let-body (cdr let-body))
  180.              (setq gen-args (pop let-body))
  181.              (when let-bindings
  182.                  
  183.                  ;; The first transformation we want to perform is
  184.                  ;; "LET-eversion": turn (let* ((generator (let (..bindings..)
  185.                  ;; #'(lambda ...)))) ..body..) into (let* (..bindings..
  186.                  ;; (generator #'(lambda ...))) ..body..).  This
  187.                  ;; transformation is valid if nothing in body refers to any
  188.                  ;; of the bindings, something we can assure by
  189.                  ;; alpha-converting the inner let (substituting new names for
  190.                  ;; each var).  Of course, none of those vars can be special,
  191.                  ;; but we already checked for that above.
  192.                  (multiple-value-setq (let-bindings renamed-vars)
  193.                         (rename-let-bindings let-bindings binding-type 
  194.                                iterate-env leftover-body #'get-iterate-temp))
  195.                  (setq leftover-body nil)
  196.                                                ; If there was any leftover
  197.                                                ; from previous, it is now
  198.                                                ; consumed
  199.                  )
  200.              
  201.              ;; The second transformation is substituting the body of the
  202.              ;; generator (LAMBDA (finish-arg) . gen-body) for its appearance
  203.              ;; in the update form (funcall generator #'(lambda ()
  204.              ;; finish-form)), then simplifying that form.  The requirement
  205.              ;; for this part is that the generator body not refer to any
  206.              ;; variables that are bound between the generator binding and the
  207.              ;; appearance in the loop body.  The only variables bound in that
  208.              ;; interval are generator temporaries, which have unique names so
  209.              ;; are no problem, and the iteration variables remaining for
  210.              ;; subsequent clauses.  We'll discover the story as we walk the
  211.              ;; body.
  212.              (multiple-value-bind
  213.               (finishdecl other rest)
  214.               (parse-declarations let-body gen-args)
  215.               (declare (ignore finishdecl))
  216.                                                ; Pull out declares, if any,
  217.                                                ; separating out the one(s)
  218.                                                ; referring to the finish arg,
  219.                                                ; which we will throw away
  220.               (when other
  221.                                                ; Combine remaining decls with
  222.                                                ; decls extracted from the LET,
  223.                                                ; if any
  224.                   (setq otherdecls (nconc otherdecls other)))
  225.               (setq let-body (cond
  226.                               (otherdecls
  227.                                                ; There are interesting
  228.                                                ; declarations, so have to keep
  229.                                                ; it wrapped.
  230.                                `(let nil (declare ,@otherdecls)
  231.                                      ,@rest))
  232.                               ((null (cdr rest))
  233.                                                ; Only one form left
  234.                                (first rest))
  235.                               (t `(progn ,@rest)))))
  236.              (unless (eq (setq let-body (iterate-transform-body let-body 
  237.                                                iterate-env renamed-vars
  238.                                                (first gen-args)
  239.                                                finish-form bound-vars clause))
  240.                          :abort)
  241.                  
  242.                  ;; Skip the rest if transformation failed.  Warning has
  243.                  ;; already been issued.
  244.                  
  245.                  ;; Note possible further optimization: if LET-BODY expanded
  246.                  ;; into (prog1 oldvalue prepare-for-next-iteration), as so
  247.                  ;; many do, then we could in most cases split the PROG1 into
  248.                  ;; two pieces: do the (setq var oldvalue) here, and do the
  249.                  ;; prepare-for-next-iteration at the bottom of the loop. 
  250.                  ;; This does a slight optimization of the PROG1 and also
  251.                  ;; rearranges the code in a way that a reasonably clever
  252.                  ;; compiler might detect how to get rid of redundant
  253.                  ;; variables altogether (such as happens with INTERVAL and
  254.                  ;; LIST-TAILS); that would make the whole thing closer to
  255.                  ;; what you might have coded by hand.  However, to do this
  256.                  ;; optimization, we need to assure that (a) the
  257.                  ;; prepare-for-next-iteration refers freely to no vars other
  258.                  ;; than the internal vars we have extracted from the LET, and
  259.                  ;; (b) that the code has no side effects.  These are both
  260.                  ;; true for all the iterators defined by this module, but how
  261.                  ;; shall we represent side-effect info and/or tap into the
  262.                  ;; compiler's knowledge of same?
  263.                  (when localdecls
  264.                                                ; There were declarations for
  265.                                                ; the generator locals--have to
  266.                                                ; keep them for later, and
  267.                                                ; rename the vars mentioned
  268.                      (setq
  269.                       generator-decls
  270.                       (nconc
  271.                        generator-decls
  272.                        (mapcar
  273.                         #'(lambda
  274.                            (decl)
  275.                            (let ((head (car decl)))
  276.                                 (cons head (if (eq head 'type)
  277.                                                (cons (second decl)
  278.                                                      (sublis renamed-vars
  279.                                                             (cddr decl)))
  280.                                                (sublis renamed-vars
  281.                                                       (cdr decl))))))
  282.                         localdecls)))))))
  283.            
  284.            ;; Finished analyzing clause now.  LET-BODY is the form which, when
  285.            ;; evaluated, returns updated values for the iteration variable(s)
  286.            ;; VARS.
  287.            (when (eq let-body :abort)
  288.                
  289.                ;; Some punt case: go with the formal semantics: bind a var to
  290.                ;; the generator, then call it in the update section
  291.                (let
  292.                 ((gvar (get-iterate-temp))
  293.                  (generator (second clause)))
  294.                 (setq
  295.                  let-bindings
  296.                  (list (list gvar
  297.                              (cond
  298.                               (leftover-body
  299.                                                ; Have to use this up
  300.                                `(progn ,@(prog1 leftover-body (setq 
  301.                                                                   leftover-body
  302.                                                                     nil))
  303.                                        generator))
  304.                               (t generator)))))
  305.                 (setq let-body `(funcall ,gvar #'(lambda nil ,finish-form)))))
  306.            (push (mv-setq (copy-list vars)
  307.                         let-body)
  308.                  update-forms)
  309.            (dolist (v vars)
  310.            #-excl
  311.                (declare (ignore v))
  312.                                                ; Pop off the vars we have now
  313.                                                ; bound from the list of vars
  314.                                                ; to watch out for--we'll bind
  315.                                                ; them right now
  316.                (pop bound-vars))
  317.            (setq bindings
  318.                  (nconc bindings let-bindings
  319.                         (cond (extra-body
  320.                                                ; There was some computation to
  321.                                                ; do after the bindings--here's
  322.                                                ; our chance
  323.                                (cons (list (first vars)
  324.                                            `(progn ,@extra-body nil))
  325.                                      (rest vars)))
  326.                               (t vars))))))))))
  327.   (do ((tail body (cdr tail)))
  328.       ((not (and (consp tail)
  329.                  (consp (car tail))
  330.                  (eq (caar tail)
  331.                      'declare)))
  332.        
  333.        ;; TAIL now points at first non-declaration.  If there were
  334.        ;; declarations, pop them off so they appear in the right place
  335.        (unless (eq tail body)
  336.            (setq iterate-decls (ldiff body tail))
  337.            (setq body tail))))
  338.   `(block ,block-name
  339.        (let* ,bindings ,@(and generator-decls
  340.                               `((declare ,@generator-decls)))
  341.              ,@iterate-decls
  342.              ,@leftover-body
  343.              (loop ,@(nreverse update-forms)
  344.                    ,@body)))))
  345.  
  346. (defun expand-into-let (clause parent-name env)
  347.        
  348.        ;; Return values: Body, LET[*], bindings, localdecls, otherdecls, extra
  349.        ;; body, where BODY is a single form.  If multiple forms in a LET, the
  350.        ;; preceding forms are returned as extra body.  Returns :ABORT if it
  351.        ;; issued a punt warning.
  352.        (prog ((expansion clause)
  353.               expandedp binding-type let-bindings let-body)
  354.              expand
  355.              (multiple-value-setq (expansion expandedp)
  356.                     (macroexpand-1 expansion env))
  357.              (cond ((not (consp expansion))
  358.                                                ; Shouldn't happen
  359.                     )
  360.                    ((symbolp (setq binding-type (first expansion)))
  361.                     (case binding-type
  362.                         ((let let*) 
  363.                            (setq let-bindings (second expansion))
  364.                                                ; List of variable bindings
  365.                            (setq let-body (cddr expansion))
  366.                            (go handle-let))))
  367.                    ((and (consp binding-type)
  368.                          (eq (car binding-type)
  369.                              'lambda)
  370.                          (not (find-if #'(lambda (x)
  371.                                                 (member x lambda-list-keywords
  372.                                                         :test #'eq)
  373.                                                 )
  374.                                      (setq let-bindings (second binding-type)))
  375.                               )
  376.                          (eql (length (the list (second expansion)))
  377.                               (length (the list let-bindings)))
  378.                          (null (cddr expansion)))
  379.                                                ; A simple LAMBDA form can be
  380.                                                ; treated as LET
  381.                     (setq let-body (cddr binding-type))
  382.                     (setq let-bindings (mapcar #'list let-bindings (second
  383.                                                                     expansion))
  384.                           )
  385.                     (setq binding-type 'let)
  386.                     (go handle-let)))
  387.              
  388.              ;; Fall thru if not a LET 
  389.              (cond (expandedp                  ; try expanding again
  390.                           (go expand))
  391.                    (t                          ; Boring--return form as the
  392.                                                ; body
  393.                       (return expansion)))
  394.              handle-let
  395.              (return (let ((locals (variables-from-let let-bindings))
  396.                            extra-body specials)
  397.                           (multiple-value-bind
  398.                            (localdecls otherdecls let-body)
  399.                            (parse-declarations let-body locals)
  400.                            (cond ((setq specials (extract-special-bindings
  401.                                                   locals localdecls))
  402.                                   (maybe-warn (cond ((find-if #'variable-globally-special-p
  403.                                                             specials)
  404.                                                ; This could be the fault of a
  405.                                                ; user proclamation
  406.                                                      :user)
  407.                                                     (t :definition))
  408.                                          
  409.           "Couldn't optimize ~S because expansion of ~S binds specials ~(~S ~)"
  410.                                          parent-name clause specials)
  411.                                   :abort)
  412.                                  (t (values (cond ((not (consp let-body))
  413.                                                    
  414.                                                ; Null body of LET?  unlikely,
  415.                                                ; but someone else will likely
  416.                                                ; complain
  417.                                                    nil)
  418.                                                   ((null (cdr let-body))
  419.                                                    
  420.                                                ; A single expression, which we
  421.                                                ; hope is (function
  422.                                                ; (lambda...))
  423.                                                    (first let-body))
  424.                                                   (t 
  425.  
  426.                           ;; More than one expression.  These are forms to
  427.                           ;; evaluate after the bindings but before the
  428.                           ;; generator form is returned.  Save them to
  429.                           ;; evaluate in the next convenient place.  Note that
  430.                           ;; this is ok, as there is no construct that can
  431.                           ;; cause a LET to return prematurely (without
  432.                           ;; returning also from some surrounding construct).
  433.                                                      (setq extra-body
  434.                                                            (butlast let-body))
  435.                                                      (car (last let-body))))
  436.                                            binding-type let-bindings localdecls
  437.                                            otherdecls extra-body))))))))
  438.  
  439. (defun variables-from-let (bindings)
  440.        
  441.        ;; Return a list of the variables bound in the first argument to LET[*].
  442.        (mapcar #'(lambda (binding)
  443.                         (if (consp binding)
  444.                             (first binding)
  445.                             binding))
  446.               bindings))
  447.  
  448. (defun iterate-transform-body (let-body iterate-env renamed-vars finish-arg 
  449.                                      finish-form bound-vars clause)
  450.        
  451.  
  452. ;;; This is the second major transformation for a single iterate clause. 
  453. ;;; LET-BODY is the body of the iterator after we have extracted its local
  454. ;;; variables and declarations.  We have two main tasks: (1) Substitute
  455. ;;; internal temporaries for occurrences of the LET variables; the alist
  456. ;;; RENAMED-VARS specifies this transformation.  (2) Substitute evaluation of
  457. ;;; FINISH-FORM for any occurrence of (funcall FINISH-ARG).  Along the way, we
  458. ;;; check for forms that would invalidate these transformations: occurrence of
  459. ;;; FINISH-ARG outside of a funcall, and free reference to any element of
  460. ;;; BOUND-VARS.  CLAUSE & TYPE are the original ITERATE clause and its type
  461. ;;; (ITERATE or ITERATE*), for purpose of error messages.  On success, we
  462. ;;; return the transformed body; on failure, :ABORT.
  463.  
  464.        (walk-form let-body iterate-env
  465.               #'(lambda (form context env)
  466.                        (declare (ignore context))
  467.                        
  468.                        ;; Need to substitute RENAMED-VARS, as well as turn
  469.                        ;; (FUNCALL finish-arg) into the finish form
  470.                        (cond ((symbolp form)
  471.                               (let (renaming)
  472.                                    (cond ((and (eq form finish-arg)
  473.                                                (variable-same-p form env 
  474.                                                       iterate-env))
  475.                                                ; An occurrence of the finish
  476.                                                ; arg outside of FUNCALL
  477.                                                ; context--I can't handle this
  478.                                           (maybe-warn :definition "Couldn't optimize iterate form because generator ~S does something with its FINISH arg besides FUNCALL it."
  479.                                                  (second clause))
  480.                                           (return-from iterate-transform-body 
  481.                                                  :abort))
  482.                                          ((and (setq renaming (assoc form 
  483.                                                                    renamed-vars
  484.                                                                    :test #'eq))
  485.                                                (variable-same-p form env 
  486.                                                       iterate-env))
  487.                                                ; Reference to one of the vars
  488.                                                ; we're renaming
  489.                                           (cdr renaming))
  490.                                          ((and (member form bound-vars :test #'eq)
  491.                                                (variable-same-p form env 
  492.                                                       iterate-env))
  493.                                                ; FORM is a var that is bound
  494.                                                ; in this same ITERATE, or
  495.                                                ; bound later in this ITERATE*.
  496.                                                ; This is a conflict.
  497.                                           (maybe-warn :user "Couldn't optimize iterate form because generator ~S is closed over ~S, in conflict with a subsequent iteration variable."
  498.                                                  (second clause)
  499.                                                  form)
  500.                                           (return-from iterate-transform-body 
  501.                                                  :abort))
  502.                                          (t form))))
  503.                              ((and (consp form)
  504.                                    (eq (first form)
  505.                                        'funcall)
  506.                                    (eq (second form)
  507.                                        finish-arg)
  508.                                    (variable-same-p (second form)
  509.                                           env iterate-env))
  510.                                                ; (FUNCALL finish-arg) =>
  511.                                                ; finish-form
  512.                               (unless (null (cddr form))
  513.                                   (maybe-warn :definition 
  514.         "Generator for ~S applied its finish arg to > 0 arguments ~S--ignored."
  515.                                          (second clause)
  516.                                          (cddr form)))
  517.                               finish-form)
  518.                              (t form)))))
  519.  
  520. (defun
  521.  parse-declarations
  522.  (tail locals)
  523.  
  524.  ;; Extract the declarations from the head of TAIL and divide them into 2
  525.  ;; classes: declares about variables in the list LOCALS, and all other
  526.  ;; declarations.  Returns 3 values: those 2 lists plus the remainder of TAIL.
  527.  (let
  528.   (localdecls otherdecls form)
  529.   (loop
  530.    (unless (and tail (consp (setq form (car tail)))
  531.                 (eq (car form)
  532.                     'declare))
  533.        (return (values localdecls otherdecls tail)))
  534.    (mapc
  535.     #'(lambda
  536.        (decl)
  537.        (case (first decl)
  538.            ((inline notinline optimize) 
  539.                                                ; These don't talk about vars
  540.               (push decl otherdecls))
  541.            (t                                  ; Assume all other kinds are
  542.                                                ; for vars
  543.               (let* ((vars (if (eq (first decl)
  544.                                    'type)
  545.                                (cddr decl)
  546.                                (cdr decl)))
  547.                      (l (intersection locals vars))
  548.                      other)
  549.                     (cond
  550.                      ((null l)
  551.                                                ; None talk about LOCALS
  552.                       (push decl otherdecls))
  553.                      ((null (setq other (set-difference vars l)))
  554.                                                ; All talk about LOCALS
  555.                       (push decl localdecls))
  556.                      (t                        ; Some of each
  557.                         (let ((head (cons 'type (and (eq (first decl)
  558.                                                          'type)
  559.                                                      (list (second decl))))))
  560.                              (push (append head other)
  561.                                    otherdecls)
  562.                              (push (append head l)
  563.                                    localdecls))))))))
  564.     (cdr form))
  565.    (pop tail))))
  566.  
  567. (defun extract-special-bindings (vars decls)
  568.        
  569.        ;; Return the subset of VARS that are special, either globally or
  570.        ;; because of a declaration in DECLS
  571.        (let ((specials (remove-if-not #'variable-globally-special-p vars)))
  572.             (dolist (d decls)
  573.                 (when (eq (car d)
  574.                           'special)
  575.                     (setq specials (union specials (intersection vars
  576.                                                           (cdr d))))))
  577.             specials))
  578.  
  579. (defun function-lambda-p (form &optional nargs)
  580.        
  581.        ;; If FORM is #'(LAMBDA bindings . body) and bindings is of length
  582.        ;; NARGS, return the lambda expression
  583.        (let (args body)
  584.             (and (consp form)
  585.                  (eq (car form)
  586.                      'function)
  587.                  (consp (setq form (cdr form)))
  588.                  (null (cdr form))
  589.                  (consp (setq form (car form)))
  590.                  (eq (car form)
  591.                      'lambda)
  592.                  (consp (setq body (cdr form)))
  593.                  (listp (setq args (car body)))
  594.                  (or (null nargs)
  595.                      (eql (length (the list args))
  596.                           nargs))
  597.                  form)))
  598.  
  599. (defun
  600.  rename-let-bindings
  601.  (let-bindings binding-type env leftover-body &optional tempvarfn)
  602.  
  603.  ;; Perform the alpha conversion required for "LET eversion" of (LET[*]
  604.  ;; LET-BINDINGS . body)--rename each of the variables to an internal name. 
  605.  ;; Returns 2 values: a new set of LET bindings and the alist of old var names
  606.  ;; to new (so caller can walk the body doing the rest of the renaming). 
  607.  ;; BINDING-TYPE is one of LET or LET*.  LEFTOVER-BODY is optional list of
  608.  ;; forms that must be eval'ed before the first binding happens.  ENV is the
  609.  ;; macro expansion environment, in case we have to walk a LET*.  TEMPVARFN is
  610.  ;; a function of no args to return a temporary var; if omitted, we use
  611.  ;; GENSYM.
  612.  (let
  613.   (renamed-vars)
  614.   (values (mapcar #'(lambda (binding)
  615.                            (let ((valueform (cond ((not (consp binding))
  616.                                                    
  617.                                                ; No initial value
  618.                                                    nil)
  619.                                                   ((or (eq binding-type
  620.                                                            'let)
  621.                                                        (null renamed-vars))
  622.                                                    
  623.                                                ; All bindings are in parallel,
  624.                                                ; so none can refer to others
  625.                                                    (second binding))
  626.                                                   (t 
  627.                                                ; In a LET*, have to substitute
  628.                                                ; vars in the 2nd and
  629.                                                ; subsequent initialization
  630.                                                ; forms
  631.                                                      (rename-variables
  632.                                                       (second binding)
  633.                                                       renamed-vars env))))
  634.                                  (newvar (if tempvarfn
  635.                                              (funcall tempvarfn)
  636.                                              (gensym))))
  637.                                 (push (cons (if (consp binding)
  638.                                                 (first binding)
  639.                                                 binding)
  640.                                             newvar)
  641.                                       renamed-vars)
  642.                                                ; Add new variable to the list
  643.                                                ; AFTER we have walked the
  644.                                                ; initial value form
  645.                                 (when leftover-body
  646.                                     
  647.  
  648.                           ;; Previous clause had some computation to do after
  649.                           ;; its bindings.  Here is the first opportunity to
  650.                           ;; do it
  651.                                     (setq valueform `(progn ,@leftover-body
  652.                                                             ,valueform))
  653.                                     (setq leftover-body nil))
  654.                                 (list newvar valueform)))
  655.                  let-bindings)
  656.          renamed-vars)))
  657.  
  658. (defun rename-variables (form alist env)
  659.        
  660.        ;; Walks FORM, renaming occurrences of the key variables in ALIST with
  661.        ;; their corresponding values.  ENV is FORM's environment, so we can
  662.        ;; make sure we are talking about the same variables.
  663.        (walk-form form env
  664.               #'(lambda (form context subenv)
  665.                        (declare (ignore context))
  666.                        (let (pair)
  667.                             (cond ((and (symbolp form)
  668.                                         (setq pair (assoc form alist :test #'eq))
  669.                                         (variable-same-p form subenv env))
  670.                                    (cdr pair))
  671.                                   (t form))))))
  672.  
  673. (defun
  674.  mv-setq
  675.  (vars expr)
  676.  
  677.  ;; Produces (MULTIPLE-VALUE-SETQ vars expr), except that I'll optimize some
  678.  ;; of the simple cases for benefit of compilers that don't, and I don't care
  679.  ;; what the value is, and I know that the variables need not be set in
  680.  ;; parallel, since they can't be used free in EXPR
  681.  (cond
  682.   ((null vars)
  683.                                                ; EXPR is a side-effect
  684.    expr)
  685.   ((not (consp vars))
  686.                                                ; This is an error, but I'll
  687.                                                ; let MULTIPLE-VALUE-SETQ
  688.                                                ; report it
  689.    `(multiple-value-setq ,vars ,expr))
  690.   ((and (listp expr)
  691.         (eq (car expr)
  692.             'values))
  693.    
  694.    ;; (mv-setq (a b c) (values x y z)) can be reduced to a parallel setq
  695.    ;; (psetq returns nil, but I don't care about returned value).  Do this
  696.    ;; even for the single variable case so that we catch (mv-setq (a) (values
  697.    ;; x y))
  698.    (pop expr)
  699.                                                ; VALUES
  700.    `(setq ,@(mapcon #'(lambda (tail)
  701.                              (list (car tail)
  702.                                    (cond ((or (cdr tail)
  703.                                               (null (cdr expr)))
  704.                                                ; One result expression for
  705.                                                ; this var
  706.                                           (pop expr))
  707.                                          (t    ; More expressions than vars,
  708.                                                ; so arrange to evaluate all
  709.                                                ; the rest now.
  710.                                             (cons 'prog1 expr)))))
  711.                    vars)))
  712.   ((null (cdr vars))
  713.                                                ; Simple one variable case
  714.    `(setq ,(car vars)
  715.           ,expr))
  716.   (t                                           ; General case--I know nothing
  717.      `(multiple-value-setq ,vars ,expr))))
  718.  
  719. (defun variable-same-p (var env1 env2)
  720.        (eq (variable-lexical-p var env1)
  721.            (variable-lexical-p var env2)))
  722.  
  723. (defun maybe-warn (type &rest warn-args)
  724.        
  725.        ;; Issue a warning about not being able to optimize this thing.  TYPE
  726.        ;; is one of :DEFINITION, meaning the definition is at fault, and
  727.        ;; :USER, meaning the user's code is at fault.
  728.        (when (case *iterate-warnings*
  729.                  ((nil) nil)
  730.                  ((:user) (eq type :user))
  731.                  (t t))
  732.            (apply #'warn warn-args)))
  733.  
  734.  
  735. ;; Sample iterators
  736.  
  737.  
  738. (defmacro
  739.  interval
  740.  (&whole whole &key from downfrom to downto above below by type)
  741.  (cond
  742.   ((and from downfrom)
  743.    (error "Can't use both FROM and DOWNFROM in ~S" whole))
  744.   ((cdr (remove nil (list to downto above below)))
  745.    (error "Can't use more than one limit keyword in ~S" whole))
  746.   (t
  747.    (let*
  748.     ((down (or downfrom downto above))
  749.      (limit (or to downto above below))
  750.      (inc (cond ((null by)
  751.                  1)
  752.                 ((constantp by)
  753.                                                ; Can inline this increment
  754.                  by))))
  755.     `(let
  756.       ((from ,(or from downfrom 0))
  757.        ,@(and limit `((to ,limit)))
  758.        ,@(and (null inc)
  759.               `((by ,by))))
  760.       ,@(and type `((declare (type ,type from ,@(and limit '(to))
  761.                                    ,@(and (null inc)
  762.                                           `(by))))))
  763.       #'(lambda
  764.          (finish)
  765.          ,@(cond ((null limit)
  766.                                                ; We won't use the FINISH arg
  767.                   '((declare (ignore finish)))))
  768.          (prog1 ,(cond (limit                  ; Test the limit.  If ok,
  769.                                                ; return current value and
  770.                                                ; increment, else quit
  771.                               `(if (,(cond (above '>)
  772.                                            (below '<)
  773.                                            (down '>=)
  774.                                            (t '<=))
  775.                                     from to)
  776.                                    from
  777.                                    (funcall finish)))
  778.                        (t                      ; No test
  779.                           'from))
  780.              (setq from (,(if down
  781.                               '-
  782.                               '+)
  783.                          from
  784.                          ,(or inc 'by))))))))))
  785.  
  786. (defmacro list-elements (list &key (by '#'cdr))
  787.        `(let ((tail ,list))
  788.              #'(lambda (finish)
  789.                       (prog1 (if (endp tail)
  790.                                  (funcall finish)
  791.                                  (first tail))
  792.                           (setq tail (funcall ,by tail))))))
  793.  
  794. (defmacro list-tails (list &key (by '#'cdr))
  795.        `(let ((tail ,list))
  796.              #'(lambda (finish)
  797.                       (prog1 (if (endp tail)
  798.                                  (funcall finish)
  799.                                  tail)
  800.                           (setq tail (funcall ,by tail))))))
  801.  
  802. (defmacro
  803.  elements
  804.  (sequence)
  805.  "Generates successive elements of SEQUENCE, with second value being the index.  Use (ELEMENTS (THE type arg)) if you care about the type."
  806.  (let*
  807.   ((type (and (consp sequence)
  808.               (eq (first sequence)
  809.                   'the)
  810.               (second sequence)))
  811.    (accessor (if type
  812.                  (sequence-accessor type)
  813.                  'elt))
  814.    (listp (eq type 'list)))
  815.   
  816.   ;; If type is given via THE, we may be able to generate a good accessor here
  817.   ;; for the benefit of implementations that aren't smart about (ELT (THE
  818.   ;; STRING FOO)).  I'm not bothering to keep the THE inside the body,
  819.   ;; however, since I assume any compiler that would understand (AREF (THE
  820.   ;; SIMPLE-ARRAY S)) would also understand that (AREF S) is the same when I
  821.   ;; bound S to (THE SIMPLE-ARRAY foo) and never modified it.
  822.   
  823.   ;; If sequence is declared to be a list, it's better to cdr down it, so we
  824.   ;; have some extra cases here.  Normally folks would write LIST-ELEMENTS,
  825.   ;; but maybe they wanted to get the index for free...
  826.   `(let* ((index 0)
  827.           (s ,sequence)
  828.           ,@(and (not listp)
  829.                  '((size (length s)))))
  830.          #'(lambda (finish)
  831.                   (values (cond ,(if listp
  832.                                      '((not (endp s))
  833.                                        (pop s))
  834.                                      `((< index size)
  835.                                        (,accessor s index)))
  836.                                 (t (funcall finish)))
  837.                          (prog1 index
  838.                              (setq index (1+ index))))))))
  839.  
  840. (defmacro
  841.  plist-elements
  842.  (plist)
  843.  "Generates each time 2 items, the indicator and the value."
  844.  `(let ((tail ,plist))
  845.        #'(lambda (finish)
  846.                 (values (if (endp tail)
  847.                             (funcall finish)
  848.                             (first tail))
  849.                        (prog1 (if (endp (setq tail (cdr tail)))
  850.                                   (funcall finish)
  851.                                   (first tail))
  852.                            (setq tail (cdr tail)))))))
  853.  
  854. (defun sequence-accessor (type)
  855.        
  856.        ;; returns the function with which most efficiently to make accesses to
  857.        ;; a sequence of type TYPE.
  858.        (case (if (consp type)
  859.                                                ; e.g., (VECTOR FLOAT *)
  860.                  (car type)
  861.                  type)
  862.            ((array simple-array vector) 'aref)
  863.            (simple-vector 'svref)
  864.            (string 'char)
  865.            (simple-string 'schar)
  866.            (bit-vector 'bit)
  867.            (simple-bit-vector 'sbit)
  868.            (t 'elt)))
  869.  
  870.  
  871. ;; These "iterators" may be withdrawn
  872.  
  873.  
  874. (defmacro eachtime (expr)
  875.        `#'(lambda (finish)
  876.                  (declare (ignore finish))
  877.                  ,expr))
  878.  
  879. (defmacro while (expr)
  880.        `#'(lambda (finish)
  881.                  (unless ,expr (funcall finish))))
  882.  
  883. (defmacro until (expr)
  884.        `#'(lambda (finish)
  885.                  (when ,expr (funcall finish))))
  886.  
  887.                                                ; GATHERING macro
  888.  
  889.  
  890. (defmacro gathering (clauses &body body &environment env)
  891.        (or (optimize-gathering-form clauses body env)
  892.            (simple-expand-gathering-form clauses body env)))
  893.  
  894. (defmacro with-gathering (clauses gather-body &body use-body)
  895.        "Binds the variables specified in CLAUSES to the result of (GATHERING clauses gather-body) and evaluates the forms in USE-BODY inside that contour."
  896.        
  897.        ;; We may optimize this a little better later for those compilers that
  898.        ;; don't do a good job on (m-v-bind vars (... (values ...)) ...).
  899.        `(multiple-value-bind ,(mapcar #'car clauses)
  900.                (gathering ,clauses ,gather-body)
  901.                ,@use-body))
  902.  
  903. (defun
  904.  simple-expand-gathering-form
  905.  (clauses body env)
  906.  (declare (ignore env))
  907.  
  908.  ;; The "formal semantics" of GATHERING.  We use this only in cases that can't
  909.  ;; be optimized.
  910.  (let
  911.   ((acc-names (mapcar #'first (if (symbolp clauses)
  912.                                                ; Shorthand using anonymous
  913.                                                ; gathering site
  914.                                   (setq clauses `((*anonymous-gathering-site*
  915.                                                    (,clauses))))
  916.                                   clauses)))
  917.    (realizer-names (mapcar #'(lambda (binding)
  918.                                     (declare (ignore binding))
  919.                                     (gensym))
  920.                           clauses)))
  921.   `(multiple-value-call
  922.     #'(lambda
  923.        ,(mapcan #'list acc-names realizer-names)
  924.        (flet ((gather (value &optional (accumulator *anonymous-gathering-site*)
  925.                              )
  926.                      (funcall accumulator value)))
  927.              ,@body
  928.              (values ,@(mapcar #'(lambda (rname)
  929.                                         `(funcall ,rname))
  930.                               realizer-names))))
  931.     ,@(mapcar #'second clauses))))
  932.  
  933. (defvar *active-gatherers* nil 
  934.        "List of GATHERING bindings currently active during macro expansion)")
  935.  
  936. (defvar *anonymous-gathering-site* nil "Variable used in formal expansion of an abbreviated GATHERING form (one with anonymous gathering site)."
  937.        )
  938.  
  939. (defun
  940.  optimize-gathering-form
  941.  (clauses body gathering-env)
  942.  (let*
  943.   (acc-info leftover-body top-bindings finish-forms top-decls)
  944.   (dolist (clause (if (symbolp clauses)
  945.                                                ; A shorthand
  946.                       `((*anonymous-gathering-site* (,clauses)))
  947.                       clauses))
  948.       (multiple-value-bind
  949.        (let-body binding-type let-bindings localdecls otherdecls extra-body)
  950.        (expand-into-let (second clause)
  951.               'gathering gathering-env)
  952.        (prog*
  953.         ((acc-var (first clause))
  954.          renamed-vars accumulator realizer)
  955.         (when (and (consp let-body)
  956.                    (eq (car let-body)
  957.                        'values)
  958.                    (consp (setq let-body (cdr let-body)))
  959.                    (setq accumulator (function-lambda-p (car let-body)))
  960.                    (consp (setq let-body (cdr let-body)))
  961.                    (setq realizer (function-lambda-p (car let-body)
  962.                                          0))
  963.                    (null (cdr let-body)))
  964.             
  965.             ;; Macro returned something of the form (VALUES #'(lambda (value)
  966.             ;; ...) #'(lambda () ...)), a function to accumulate values and a
  967.             ;; function to realize the result.
  968.             (when binding-type
  969.                 
  970.                 ;; Gatherer expanded into a LET
  971.                 (cond (otherdecls (maybe-warn :definition "Couldn't optimize GATHERING clause ~S because its expansion carries declarations about more than the bound variables: ~S"
  972.                                          (second clause)
  973.                                          `(declare ,@otherdecls))
  974.                              (go punt)))
  975.                 (when let-bindings
  976.                     
  977.                     ;; The first transformation we want to perform is a
  978.                     ;; variant of "LET-eversion": turn (mv-bind (acc real)
  979.                     ;; (let (..bindings..) (values #'(lambda ...) #'(lambda
  980.                     ;; ...))) ..body..) into (let* (..bindings.. (acc
  981.                     ;; #'(lambda ...)) (real #'(lambda ...))) ..body..).  This
  982.                     ;; transformation is valid if nothing in body refers to
  983.                     ;; any of the bindings, something we can assure by
  984.                     ;; alpha-converting the inner let (substituting new names
  985.                     ;; for each var).  Of course, none of those vars can be
  986.                     ;; special, but we already checked for that above.
  987.                     (multiple-value-setq (let-bindings renamed-vars)
  988.                            (rename-let-bindings let-bindings binding-type 
  989.                                   gathering-env leftover-body))
  990.                     (setq top-bindings (nconc top-bindings let-bindings))
  991.                     (setq leftover-body nil)
  992.                                                ; If there was any leftover
  993.                                                ; from previous, it is now
  994.                                                ; consumed
  995.                     ))
  996.             (setq leftover-body (nconc leftover-body extra-body))
  997.                                                ; Computation to do after these
  998.                                                ; bindings
  999.             (push (cons acc-var (rename-and-capture-variables accumulator 
  1000.                                        renamed-vars gathering-env))
  1001.                   acc-info)
  1002.             (setq realizer (rename-variables realizer renamed-vars 
  1003.                                   gathering-env))
  1004.             (push (cond ((null (cdddr realizer))
  1005.                                                ; Simple (LAMBDA () expr) =>
  1006.                                                ; expr
  1007.                          (third realizer))
  1008.                         (t                     ; There could be declarations
  1009.                                                ; or something, so leave as a
  1010.                                                ; LET
  1011.                            (cons 'let (cdr realizer))))
  1012.                   finish-forms)
  1013.             (unless (null localdecls)
  1014.                                                ; Declarations about the LET
  1015.                                                ; variables also has to
  1016.                                                ; percolate up
  1017.                 (setq top-decls (nconc top-decls (sublis renamed-vars 
  1018.                                                         localdecls))))
  1019.             (return))
  1020.         (maybe-warn :definition "Couldn't optimize GATHERING clause ~S because its expansion is not of the form (VALUES #'(LAMBDA ...) #'(LAMBDA () ...))"
  1021.                (second clause))
  1022.         punt
  1023.         (let
  1024.          ((gs (gensym))
  1025.           (expansion `(multiple-value-list ,(second clause))))
  1026.                                                ; Slow way--bind gensym to the
  1027.                                                ; macro expansion, and we will
  1028.                                                ; funcall it in the body
  1029.          (push (list acc-var gs)
  1030.                acc-info)
  1031.          (push `(funcall (cadr ,gs))
  1032.                finish-forms)
  1033.          (setq
  1034.           top-bindings
  1035.           (nconc
  1036.            top-bindings
  1037.            (list (list gs (cond (leftover-body
  1038.                                  `(progn ,@(prog1 leftover-body
  1039.                                                   (setq leftover-body nil))
  1040.                                          ,expansion))
  1041.                                 (t expansion))))))))))
  1042.   (setq body (walk-gathering-body body gathering-env acc-info))
  1043.   (cond ((eq body :abort)
  1044.                                                ; Couldn't finish expansion
  1045.          nil)
  1046.         (t `(let* ,top-bindings
  1047.                   ,@(and top-decls `((declare ,@top-decls)))
  1048.                   ,body
  1049.                   ,(cond ((null (cdr finish-forms))
  1050.                                                ; just a single value
  1051.                           (car finish-forms))
  1052.                          (t `(values ,@(reverse finish-forms)))))))))
  1053.  
  1054. (defun rename-and-capture-variables (form alist env)
  1055.        
  1056.        ;; Walks FORM, renaming occurrences of the key variables in ALIST with
  1057.        ;; their corresponding values, and capturing any other free variables. 
  1058.        ;; Returns a list of the new form and the list of other closed-over
  1059.        ;; vars.  ENV is FORM's environment, so we can make sure we are talking
  1060.        ;; about the same variables.
  1061.        (let (closed)
  1062.             (list (walk-form
  1063.                    form env
  1064.                    #'(lambda (form context subenv)
  1065.                             (declare (ignore context))
  1066.                             (let (pair)
  1067.                                  (cond ((or (not (symbolp form))
  1068.                                             (not (variable-same-p form subenv 
  1069.                                                         env)))
  1070.                                                ; non-variable or one that has
  1071.                                                ; been rebound
  1072.                                         form)
  1073.                                        ((setq pair (assoc form alist :test #'eq))
  1074.                                                ; One to rename
  1075.                                         (cdr pair))
  1076.                                        (t      ; var is free
  1077.                                           (pushnew form closed :test #'eq)
  1078.                                           form)))))
  1079.                   closed)))
  1080.  
  1081. (defun
  1082.  walk-gathering-body
  1083.  (body gathering-env acc-info)
  1084.  
  1085.  ;; Walk the body of (GATHERING (...) . BODY) in environment GATHERING-ENV. 
  1086.  ;; ACC-INFO is a list of information about each of the gathering "bindings"
  1087.  ;; in the form, in the form (var gatheringfn freevars env)
  1088.  (let
  1089.   ((*active-gatherers* (nconc (mapcar #'car acc-info)
  1090.                               *active-gatherers*)))
  1091.   
  1092.   ;; *ACTIVE-GATHERERS* tells us what vars are currently legal as GATHER
  1093.   ;; targets.  This is so that when we encounter a GATHER not belonging to us
  1094.   ;; we can know whether to warn about it.
  1095.   (walk-form
  1096.    (cons 'progn body)
  1097.    gathering-env
  1098.    #'(lambda
  1099.       (form context env)
  1100.       (declare (ignore context))
  1101.       (let (info site)
  1102.            (cond ((consp form)
  1103.                   (cond
  1104.                    ((not (eq (car form)
  1105.                              'gather))
  1106.                                                ; We only care about GATHER
  1107.                     (when (and (eq (car form)
  1108.                                    'function)
  1109.                                (eq (cadr form)
  1110.                                    'gather))
  1111.                                                ; Passed as functional--can't
  1112.                                                ; macroexpand
  1113.                         (maybe-warn :user 
  1114.                    "Can't optimize GATHERING because of reference to #'GATHER."
  1115.                                )
  1116.                         (return-from walk-gathering-body :abort))
  1117.                     form)
  1118.                    ((setq info (assoc (setq site (if (null (cddr form))
  1119.                                                      
  1120.                                                      '
  1121.                                                      *anonymous-gathering-site*
  1122.                                                      (third form)))
  1123.                                       acc-info))
  1124.                                                ; One of ours--expand (GATHER
  1125.                                                ; value var).  INFO = (var
  1126.                                                ; gatheringfn freevars env)
  1127.                     (unless (null (cdddr form))
  1128.                            (warn "Extra arguments (> 2) in ~S discarded." form)
  1129.                            )
  1130.                     (let ((fn (second info)))
  1131.                          (cond ((symbolp fn)
  1132.                                                ; Unoptimized case--just call
  1133.                                                ; the gatherer.  FN is the
  1134.                                                ; gensym that we bound to the
  1135.                                                ; list of two values returned
  1136.                                                ; from the gatherer.
  1137.                                 `(funcall (car ,fn)
  1138.                                         ,(second form)))
  1139.                                (t              ; FN = (lambda (value) ...)
  1140.                                   (dolist (s (third info))
  1141.                                       (unless (or (variable-same-p s env 
  1142.                                                          gathering-env)
  1143.                                                   (and (variable-special-p
  1144.                                                         s env)
  1145.                                                        (variable-special-p
  1146.                                                         s gathering-env)))
  1147.                                           
  1148.  
  1149.                           ;; Some var used free in the LAMBDA form has been
  1150.                           ;; rebound between here and the parent GATHERING
  1151.                           ;; form, so can't substitute the lambda.  Ok if it's
  1152.                           ;; a special reference both here and in the LAMBDA,
  1153.                           ;; because then it's not closed over.
  1154.                                           (maybe-warn :user "Can't optimize GATHERING because the expansion closes over the variable ~S, which is rebound around a GATHER for it."
  1155.                                                  s)
  1156.                                           (return-from walk-gathering-body 
  1157.                                                  :abort)))
  1158.                                   
  1159.  
  1160.                           ;; Return ((lambda (value) ...) actual-value).  In
  1161.                           ;; many cases we could simplify this further by
  1162.                           ;; substitution, but we'd have to be careful (for
  1163.                           ;; example, we would need to alpha-convert any LET
  1164.                           ;; we found inside).  Any decent compiler will do it
  1165.                           ;; for us.
  1166.                                   (list fn (second form))))))
  1167.                    ((and (setq info (member site *active-gatherers*))
  1168.                          (or (eq site '*anonymous-gathering-site*)
  1169.                              (variable-same-p site env (fourth info))))
  1170.                                                ; Some other GATHERING will
  1171.                                                ; take care of this form, so
  1172.                                                ; pass it up for now. 
  1173.                                                ; Environment check is to make
  1174.                                                ; sure nobody shadowed it
  1175.                                                ; between here and there
  1176.                     form)
  1177.                    (t                          ; Nobody's going to handle it
  1178.                       (if (eq site '*anonymous-gathering-site*)
  1179.                                                ; More likely that she forgot
  1180.                                                ; to mention the site than
  1181.                                                ; forget to write an anonymous
  1182.                                                ; gathering.
  1183.                           (warn "There is no gathering site specified in ~S." 
  1184.                                 form)
  1185.                           (warn 
  1186.              "The site ~S in ~S is not defined in an enclosing GATHERING form."
  1187.                                 site form))
  1188.                                                ; Turn it into something else
  1189.                                                ; so we don't warn twice in the
  1190.                                                ; nested case
  1191.                       `(%orphaned-gather ,@(cdr form)))))
  1192.                  ((and (symbolp form)
  1193.                        (setq info (assoc form acc-info))
  1194.                        (variable-same-p form env gathering-env))
  1195.                                                ; A variable reference to a
  1196.                                                ; gather binding from
  1197.                                                ; environment TEM
  1198.                   (maybe-warn :user "Can't optimize GATHERING because site variable ~S is used outside of a GATHER form."
  1199.                          form)
  1200.                   (return-from walk-gathering-body :abort))
  1201.                  (t form)))))))
  1202.  
  1203.  
  1204. ;; Sample gatherers
  1205.  
  1206.  
  1207. (defmacro
  1208.  collecting
  1209.  (&key initial-value)
  1210.  `(let* ((head ,initial-value)
  1211.          (tail ,(and initial-value `(last head))))
  1212.         (values #'(lambda (value)
  1213.                          (if (null head)
  1214.                              (setq head (setq tail (list value)))
  1215.                              (setq tail (cdr (rplacd tail (list value))))))
  1216.                #'(lambda nil head))))
  1217.  
  1218. (defmacro joining (&key initial-value)
  1219.        `(let ((result ,initial-value))
  1220.              (values #'(lambda (value)
  1221.                               (setq result (nconc result value)))
  1222.                     #'(lambda nil result))))
  1223.  
  1224. (defmacro
  1225.  maximizing
  1226.  (&key initial-value)
  1227.  `(let ((result ,initial-value))
  1228.        (values
  1229.         #'(lambda (value)
  1230.                  (when ,(cond ((and (constantp initial-value)
  1231.                                     (not (null (eval initial-value))))
  1232.                                                ; Initial value is given and we
  1233.                                                ; know it's not NIL, so leave
  1234.                                                ; out the null check
  1235.                                '(> value result))
  1236.                               (t '(or (null result)
  1237.                                       (> value result))))
  1238.                        (setq result value)))
  1239.         #'(lambda nil result))))
  1240.  
  1241. (defmacro
  1242.  minimizing
  1243.  (&key initial-value)
  1244.  `(let ((result ,initial-value))
  1245.        (values
  1246.         #'(lambda (value)
  1247.                  (when ,(cond ((and (constantp initial-value)
  1248.                                     (not (null (eval initial-value))))
  1249.                                                ; Initial value is given and we
  1250.                                                ; know it's not NIL, so leave
  1251.                                                ; out the null check
  1252.                                '(< value result))
  1253.                               (t '(or (null result)
  1254.                                       (< value result))))
  1255.                        (setq result value)))
  1256.         #'(lambda nil result))))
  1257.  
  1258. (defmacro summing (&key (initial-value 0))
  1259.        `(let ((sum ,initial-value))
  1260.              (values #'(lambda (value)
  1261.                               (setq sum (+ sum value)))
  1262.                     #'(lambda nil sum))))
  1263.  
  1264.                                                ; Easier to read expanded code
  1265.                                                ; if PROG1 gets left alone
  1266.  
  1267.  
  1268. (define-walker-template prog1 (nil return walker::repeat (eval)))
  1269.  
  1270.